﻿using nhCore.Modbus;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace nhCore.Server
{
    //声明一个方法型，关键字就是delegate,有参数就带上参数
    public delegate void AnalysisResult_EventHandler(IO sender, object values, Cmd cmd);

    /// <summary>
    /// 连接，Tcp中对应Client，串口通讯中对应COM口
    /// </summary>
    public class Conn
    {
        public IO IO { get; set; }

        /// <summary>
        /// 最后连接的客户端地址，串口为串口名，TcpClient为IP地址
        /// </summary>
        public string ClientAddress { get; set; }

        /// <summary>
        /// 为flase时停止对应task
        /// </summary>
        public bool IsRunning { get; set; } = true;

        /// <summary>
        /// 本连接下的命令列表
        /// </summary>
        public List<Cmd> Cmds { get; set; } = new List<Cmd>();

        /// <summary>
        /// 服务监听器，当前对象转换为ISvrListener类型的对象的属性，可以直接通过该属性来调用接口方法
        /// </summary>
        private ISvrListener ConnListener { get; set; }

        private IMessage MsgListener { get; set; }

        public object Client { get; set; }

        private AnalysisResult_EventHandler AnalysisResult { get; set; }

        /// <summary>
        /// 新建一个连接
        /// </summary>
        /// <param name="io"></param>
        /// <param name="client"></param>
        public Conn(IO io, object client, AnalysisResult_EventHandler analysisResult)
        {
            IO = io;
            Client = client;

            if (client is System.IO.Ports.SerialPort)
            {
                ClientAddress = (client as System.IO.Ports.SerialPort).PortName;
            }
            else if (client is System.Net.Sockets.TcpClient)
            {
                ClientAddress = ((System.Net.IPEndPoint)(client as System.Net.Sockets.TcpClient).Client.RemoteEndPoint).Address.ToString() +
                    ":" + ((System.Net.IPEndPoint)(client as System.Net.Sockets.TcpClient).Client.RemoteEndPoint).Port.ToString();
            }
            else if (client is YunLinkIO)
            {
                ClientAddress = "027010.cn";
            }
            else
            {
                ClientAddress = "未知接口连接";
            }

            Task task = Task.Factory.StartNew(CmdTask);
            AnalysisResult = analysisResult;
        }

        /// <summary>
        /// 设置服务监听
        /// </summary>
        /// <param name="Listener"></param>
        public void SetListener(ISvrListener Listener, IMessage message)
        {
            ConnListener = Listener;
            MsgListener = message;//设置文字提示、Log监听
        }

        private void CmdTask()
        {
            Cmd TmpCmd = null; //当前命令
            int sleepTime = 0;

            while (IsRunning)
            {

                if (Cmds.Count > 0)
                {
                    TmpCmd = Cmds?.OrderBy(x => x.Time).First();//没设备时会为空
                    sleepTime = (int)(TmpCmd.Time - DateTime.Now).TotalMilliseconds;//计算最近命令休眠相应时间
                }

                if (Cmds.Count > 0 && sleepTime <= 0) //立即发送
                {
                    Debug.WriteLine($"立即发送{TmpCmd.SentCmd.Key}");
                    object oRead = IO.SendAccept(Client, TmpCmd.SentCmd.GetCmd());//调用函数立即发送

                    if (TmpCmd.SentCmd.IsAnswer(oRead))//效验通过，功能码、地址符合
                    {
                        Debug.WriteLine($"\t\t有回复：{TmpCmd.SentCmd.Key}");
                        TmpCmd.SentCmd.SleepState = false;
                        TmpCmd.FailedCount = 0;
                        object o = TmpCmd.SentCmd.Analyzer.Analysis(oRead);//解析
                        //ConnListener.AnalysisResult(IO, o, TmpCmd);//解析结果处理
                        AnalysisResult(IO, o, TmpCmd);//解析结果处理

                        TmpCmd.SentCmd.NextCmd();//实时类用继承基类的空方法
                    }
                    else
                    {   //无回复或回复异常
                        TmpCmd.FailedCount++;
                        Debug.WriteLine($"{ClientAddress}接口中 <{TmpCmd.SentCmd.Key}> {TmpCmd.FailedCount}次失败。");
                        if (TmpCmd.FailedCount >= 3)
                        {
                            if (TmpCmd.SentCmd.Automatic)
                            {
                                TmpCmd.SentCmd.SleepState = true;//自动命令进入SleepState
                                Debug.WriteLine("暂缓发送");
                            }
                            else
                            {
                                TmpCmd.IsDelete = true;
                                //MsgListener.Error($"{ClientAddress}接口中 <{TmpCmd.SentCmd.Key}> {TmpCmd.FailedCount}次失败，不再发送");
                                Debug.WriteLine("不再发送");
                            }
                        }
                    }

                    if (TmpCmd.IsDelete) //非Auto命令发送3次失败或任务完成即删除
                    {
                        _ = Cmds.Remove(TmpCmd);
                        if (Cmds.Count == 0)
                        {
                            IsRunning = false;
                        }
                    }
                    else
                    {
                        Debug.WriteLine($"下一条命令:{TmpCmd.SentCmd.Key},OffSet:{TmpCmd.SentCmd.OffSet},间隔:{TmpCmd.SentCmd.DelayTime}ms");
                        TmpCmd.RefreshTime();
                    }
                }
                else
                {   //休眠
                    Debug.WriteLine($"休眠时间：{sleepTime}ms");
                    Thread.Sleep(sleepTime);
                }
            }
        }
    }
}